#include "myglwidget.h"
#include <QDebug>

MyGLWidget::MyGLWidget(QWidget *parent) : QGLWidget(parent), cnt(0), cg_enable(true), wave_movement(0.0f) {
	background = Qt::black;
	connect(&timer, SIGNAL(timeout()), this, SLOT(updateGL()));
	timer.start(10);
}

MyGLWidget::~MyGLWidget() {
	cgDestroyContext(cgContext);
}

void MyGLWidget::initializeGL() {
	qDebug() << "initializeGL";
	qglClearColor(background);
	glClearDepth(1.0f);
	glDepthFunc(GL_LESS);
	glEnable(GL_DEPTH_TEST);
	//glEnable(GL_LIGHTING);
	//glEnable(GL_LIGHT0);
	glShadeModel(GL_SMOOTH);
	glClearColor (0.0f, 0.0f, 0.0f, 0.5f);								// Black Background
	glClearDepth (1.0f);												// Depth Buffer Setup
	glDepthFunc (GL_LEQUAL);											// The Type Of Depth Testing
	glEnable (GL_DEPTH_TEST);											// Enable Depth Testing
	glShadeModel (GL_SMOOTH);											// Select Smooth Shading
	glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);					// Set Perspective Calculations To Most Accurate
	/*light_ambient = new GLfloat[4];
	light_ambient[0] = 1.0;
	light_ambient[1] = 1.0;
	light_ambient[2] = 1.0;
	light_ambient[3] = 1.0;
	light_ambient_position = new GLfloat[4];
	light_ambient_position[0] = 2.0;
	light_ambient_position[1] = 2.0;
	light_ambient_position[2] = 2.0;
	light_ambient_position[3] = 1.0;
	glLightfv(GL_LIGHT0, GL_POSITION, light_ambient_position);
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, whiteDiffuseLight);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glMatrixMode(GL_PROJECTION);
	Image* image = loadBMP("krata.bmp");
	textureId = loadTexture(image);*/
	glLoadIdentity();
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	for (int x = 0; x < SIZE; x++) {
		for (int z = 0; z < SIZE; z++) {
			mesh[x][z][0] = (float) (SIZE / 2) - x;	// We Want To Center Our Mesh Around The Origin
			mesh[x][z][1] = 0.0f;					// Set The Y Values For All Points To 0
			mesh[x][z][2] = (float) (SIZE / 2) - z;	// We Want To Center Our Mesh Around The Origin
		}
	}

	// Setup Cg
	cgContext = cgCreateContext();					// Create A New Context For Our Cg Program(s)

	// Validate Our Context Generation Was Successful
	if (cgContext == 0) {
		fprintf(stderr, "Failed To Create Cg Context\n");
		exit(-1);									// We Cannot Continue
	}

	cgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);	// Get The Latest GL Vertex Profile

	// Validate Our Profile Determination Was Successful
	if (cgVertexProfile == CG_PROFILE_UNKNOWN) {
		fprintf(stderr, "Invalid profile type\n");
		exit(-1);									// We Cannot Continue
	}

	cgGLSetOptimalOptions(cgVertexProfile);			// Set The Current Profile

	// Load And Compile The Vertex Shader From File
	cgProgram = cgCreateProgramFromFile(cgContext, CG_SOURCE, "Wave.cg", cgVertexProfile, "main", 0);

	// Validate Success
	if (cgProgram == 0) {
		// We Need To Determine What Went Wrong
		CGerror Error = cgGetError();

		// Show A Message Box Explaining What Went Wrong
		qDebug() << "Error creating program: " << cgGetErrorString(Error);
		exit(-1);									// We Cannot Continue
	}

	// Load The Program
	cgGLLoadProgram(cgProgram);

	// Get Handles To Each Of Our Parameters So That
	// We Can Change Them At Will Within Our Code
	position		= cgGetNamedParameter(cgProgram, "IN.position");
	color			= cgGetNamedParameter(cgProgram, "IN.color");
	wave			= cgGetNamedParameter(cgProgram, "IN.wave");
	modelViewMatrix	= cgGetNamedParameter(cgProgram, "ModelViewProj");
}

void MyGLWidget::paintGL() {
	//qDebug() << "paintGL(): " << cnt++;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	//glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluLookAt(0.0f, 25.0f, -45.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0);

	// Set The Modelview Matrix Of Our Shader To Our OpenGL Modelview Matrix
	cgGLSetStateMatrixParameter(modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);

	if (cg_enable) {
		cgGLEnableProfile(cgVertexProfile);								// Enable Our Vertex Shader Profile

		// Bind Our Vertex Program To The Current State
		cgGLBindProgram(cgProgram);

		// Set The Drawing Color To Light Green (Can Be Changed By Shader, Etc...)
		cgGLSetParameter4f(color, 0.5f, 1.0f, 0.5f, 1.0f);
	}

	// Start Drawing Our Mesh
	for (int x = 0; x < SIZE - 1; x++) {
		// Draw A Triangle Strip For Each Column Of Our Mesh
		glBegin(GL_TRIANGLE_STRIP);
		for (int z = 0; z < SIZE - 1; z++) {
			// Set The Wave Parameter Of Our Shader To The Incremented Wave Value From Our Main Program
			cgGLSetParameter3f(wave, wave_movement, 1.0f, 1.0f);
			glVertex3f(mesh[x][z][0], mesh[x][z][1], mesh[x][z][2]);		// Draw Vertex
			glVertex3f(mesh[x+1][z][0], mesh[x+1][z][1], mesh[x+1][z][2]);	// Draw Vertex
			wave_movement += 0.00001f;										// Increment Our Wave Movement
			if (wave_movement > 6.28) {
				wave_movement -= 6.28;
			}
		}
		glEnd();
	}
	if (cg_enable) {
		cgGLDisableProfile(cgVertexProfile);							// Disable Our Vertex Profile
	}

	/*gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 1000.0f);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0, 0, 2, 0, 0, 0, -1, 1, -1);
	glBegin(GL_TRIANGLES);
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex3f(1.0f, 0.0f, 0.0f);

		glColor3f(0.0f, 1.0f, 0.0f);
		glVertex3f(0.0f, 1.0f, 0.0f);

		glColor3f(0.0f, 0.0f, 1.0f);
		glVertex3f(0.0f, 0.0f, 1.0f);
	glEnd();*/
}

void MyGLWidget::resizeGL(int width, int height) {
	try {
		qDebug() << "resize";
		height = height ? height : 1;
		this->height = height;
		this->width = width;

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();
		glViewport(0, 0, (GLint)width, (GLint)height);
		gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 1000.0f);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		qDebug() << "resized ok";
	} catch (...) {
		qDebug() << "resize errored";
	}
}

void MyGLWidget::manage_cg(bool enable) {
	cg_enable = enable;
}
